package com.yxsk.relay.job.admin.web.controller;

import com.yxsk.relay.job.admin.controller.JobController;
import com.yxsk.relay.job.admin.controller.dto.job.AddJobRequestDto;
import com.yxsk.relay.job.admin.controller.dto.job.UpdateJobRequestDto;
import com.yxsk.relay.job.admin.core.schedule.quartz.vo.JobConfig;
import com.yxsk.relay.job.admin.data.entity.BaseEntity;
import com.yxsk.relay.job.admin.data.entity.JobApps;
import com.yxsk.relay.job.admin.data.entity.JobDetails;
import com.yxsk.relay.job.admin.data.service.JobAppsService;
import com.yxsk.relay.job.admin.data.service.JobDetailService;
import com.yxsk.relay.job.admin.web.common.exception.RelayAdminWebRuntimeException;
import com.yxsk.relay.job.admin.web.controller.dto.JobRelationQueryDto;
import com.yxsk.relay.job.admin.web.service.AdminJobDetailService;
import com.yxsk.relay.job.component.common.protocol.message.base.ResultResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Stream;

/**
 * @Author 11376
 * @CreaTime 2019/6/26 23:29
 * @Description
 */
@Controller
@RequestMapping("/admin/quartz/job")
public class AdminJobController extends BaseController<JobDetails, JobDetailService> {

    @Autowired
    private AdminJobDetailService adminJobDetailService;

    @Autowired
    private JobAppsService jobAppsService;

    @Autowired
    private JobController jobController;

    @GetMapping("")
    public String index(Model model, JobDetails details) {
        // 创建匹配器，进行动态查询匹配
        ExampleMatcher matcher = ExampleMatcher.matching().
                withMatcher("title", match -> match.contains());

        details.setDelFlag(BaseEntity.DelFlagEnum.NORMAL.getFlag());

        // 获取任务数据
        Example<JobDetails> example = Example.of(details, matcher);
        Page<JobDetails> list = this.adminJobDetailService.getPageList(example);
        List<JobDetails> content = list.getContent();
        if (!CollectionUtils.isEmpty(content)) {
            content.stream().forEach(details1 -> details1.setTriggerClassName(JobDetails.TriggerClassesEnum.getTriggerByClassName(details1.getTriggerClassName()).getName()));
        }

        // 获取应用列表
        List<JobApps> appsList = this.jobAppsService.findAllNormalEntities();

        // 封装数据
        model.addAttribute("apps", appsList);
        model.addAttribute("list", list.getContent());
        model.addAttribute("page", list);
        return "/system/job/job/index";
    }

    @GetMapping("/delete")
    @ResponseBody
    public ResultResponse delete(String ids) {
        if (StringUtils.isNotBlank(ids)) {
            String[] idS = ids.split(MULTIPLE_DATA_SEPARATOR);
            if (idS != null) {
                Stream.of(idS).forEach(id -> this.service.deleteById(id));
            }
        }
        return ResultResponse.ok("删除成功");
    }

    @PostMapping("/ok")
    @ResponseBody
    public ResultResponse ok(String ids) {
        if (StringUtils.isNotBlank(ids)) {
            String[] idS = ids.split(MULTIPLE_DATA_SEPARATOR);
            if (idS != null) {
                Stream.of(idS).forEach(id -> this.service.resumeJob(id));
            }
        }
        return ResultResponse.ok("启用应用成功");
    }

    @PostMapping("/pause")
    @ResponseBody
    public ResultResponse pause(String ids) {
        if (StringUtils.isNotBlank(ids)) {
            String[] idS = ids.split(MULTIPLE_DATA_SEPARATOR);
            if (idS != null) {
                Stream.of(idS).forEach(id -> this.service.pauseJob(id));
            }
        }
        return ResultResponse.ok("暂停应用成功");
    }

    @Override
    public String detail(@PathVariable("id") String id, Model model) {
        JobDetails entity = this.service.findById(id);
        if (entity == null) {
            throw new RelayAdminWebRuntimeException("未找到相关信息");
        }
        entity.setAppId(this.jobAppsService.findById(entity.getAppId()).getAppName());
        entity.setTriggerClassName(JobDetails.TriggerClassesEnum.getTriggerByClassName(entity.getTriggerClassName()).getName());
        entity.setExecuteModel(JobConfig.ExecuteModel.getExecuteModel(entity.getExecuteModel()).getName());
        entity.setRouteStrategy(JobConfig.RouteStrategy.getStrategy(entity.getRouteStrategy()).getName());
        entity.setBlockStrategy(JobConfig.BlockStrategy.getBlockStrategy(entity.getBlockStrategy()).getName());
        entity.setStatus(JobConfig.JobStatus.getJobStatus(entity.getStatus()).getName());
        model.addAttribute("entity", entity);
        return getBasicDir() + "/detail";
    }

    @Override
    public ResultResponse save(JobDetails details) {
        if (StringUtils.isNotBlank(details.getId())) {
            UpdateJobRequestDto requestDto = new UpdateJobRequestDto();
            BeanUtils.copyProperties(details, requestDto);
            requestDto.setTriggerName(JobDetails.TriggerClassesEnum.getTriggerByClassName(details.getTriggerClassName()).getTriggerName());
            this.jobController.update(requestDto);
            return ResultResponse.ok("更新成功");
        }
        // 添加
        AddJobRequestDto requestDto = new AddJobRequestDto();
        BeanUtils.copyProperties(details, requestDto);
        requestDto.setTriggerName(JobDetails.TriggerClassesEnum.getTriggerByClassName(details.getTriggerClassName()).getTriggerName());
        this.jobController.add(requestDto);
        return ResultResponse.ok("添加成功");
    }

    @GetMapping("/toAdd")
    public String toAdd(Model model) {
        model.addAttribute("apps", this.jobAppsService.findAllNormalEntities());
        model.addAttribute("trigger", getTriggerClassName());
        model.addAttribute("executeModel", getExecuteModel());
        model.addAttribute("routeStrategy", getRouteStrategy());
        model.addAttribute("blockStrategy", getBlockStrategy());
        return super.toAdd();
    }

    @Override
    public String edit(@PathVariable("id") String id, Model model) {
        model.addAttribute("apps", this.jobAppsService.findAllNormalEntities());
        model.addAttribute("trigger", getTriggerClassName());
        model.addAttribute("executeModel", getExecuteModel());
        model.addAttribute("routeStrategy", getRouteStrategy());
        model.addAttribute("blockStrategy", getBlockStrategy());
        return super.edit(id, model);
    }

    @GetMapping("/toChild/{id}")
    public String toChild(@PathVariable("id") String id, Model model) {
        JobDetails details = this.service.findById(id);
        if (details == null) {
            throw new RelayAdminWebRuntimeException("未找到任务信息");
        }
        // 查询所有任务
        List<JobDetails> detailsList = this.service.findAllNormalEntities();
        // 查询已有的子任务
        List<JobDetails> childrenJob = this.service.getChildrenJob(id);

        List<String> childrenId = new ArrayList<>();
        if (!CollectionUtils.isEmpty(childrenJob)) {
            childrenJob.stream().forEach(details1 -> childrenId.add(details1.getId()));
        }

        if (!CollectionUtils.isEmpty(detailsList)) {
            for (JobDetails jobDetails : detailsList) {
                if (jobDetails.getId().equals(id)) {
                    detailsList.remove(jobDetails);
                    break;
                }
            }
        }

        model.addAttribute("children", childrenId);
        model.addAttribute("list", detailsList);
        return getBasicDir() + "/children";
    }

    @GetMapping("/getJobChildren/{id}")
    @ResponseBody
    public ResultResponse getJobChildren(@PathVariable("id") String id) {
        return ResultResponse.ok(buildTree(id, new HashMap<>()));
    }

    private Map<String, Object> buildTree(String id, Map<String, String> existIds) {
        String name = existIds.get(id);
        if (name == null) {
            JobDetails details = this.service.findById(id);
            name = details.getJobName();
        }
        if (name != null) {
            Map<String, Object> ret = new HashMap<>();
            ret.put("name", name);
            if (existIds.get(id) == null) {
                existIds.put(id, name);
                // 不存在该节点, 防止循环任务导致任务链查询死循环
                List<JobDetails> childrenJob = this.service.getChildrenJob(id);
                if (!CollectionUtils.isEmpty(childrenJob)) {
                    List<Map<String, Object>> children = new ArrayList<>();
                    childrenJob.forEach(jobDetails -> {
                        Map<String, Object> tree = buildTree(jobDetails.getId(), existIds);
                        if (tree != null) {
                            children.add(tree);
                        }
                    });

                    if (!children.isEmpty()) {
                        ret.put("children", children);
                    }
                }
            }
            return ret;
        }
        return null;
    }

    @PostMapping("/editChild")
    @ResponseBody
    public ResultResponse child(@RequestParam(name = "id") String id,
                                @RequestParam(name = "childId", required = false) List<String> children) {
        this.adminJobDetailService.updateChildrenJob(id, children);
        return ResultResponse.ok("更新子任务成功");
    }

    @GetMapping("/toTrigger/{id}")
    public String toTrigger(@PathVariable("id") String jobId, Model model) {
        // 查询任务信息
        JobDetails details = this.service.findById(jobId);
        if (details == null) {
            throw new RelayAdminWebRuntimeException("未找到相关任务信息");
        }
        // 查询应用信息
        JobApps apps = this.jobAppsService.findById(details.getAppId());

        model.addAttribute("job", details);
        model.addAttribute("app", apps);
        return getBasicDir() + "/trigger";
    }

    @GetMapping("/relation/{id}")
    @ResponseBody
    public ResultResponse relation(@PathVariable("id") String jobId) {
        JobRelationQueryDto queryDto = this.adminJobDetailService.getJobRelation(jobId);
        return ResultResponse.ok(queryDto);
    }

    public Map<String, String> getTriggerClassName() {
        Map<String, String> result = new HashMap<>();
        JobDetails.TriggerClassesEnum[] values = JobDetails.TriggerClassesEnum.values();
        if (values != null) {
            for (JobDetails.TriggerClassesEnum value : values) {
                result.put(value.getTriggerClass().getName(), value.getName());
            }
        }
        return result;
    }

    public Map<String, String> getExecuteModel() {
        Map<String, String> result = new HashMap<>();
        JobConfig.ExecuteModel[] values = JobConfig.ExecuteModel.values();
        if (values != null) {
            for (JobConfig.ExecuteModel value : values) {
                result.put(value.getModel(), value.getName());
            }
        }
        return result;
    }

    public Map<String, String> getRouteStrategy() {
        Map<String, String> result = new HashMap<>();
        JobConfig.RouteStrategy[] values = JobConfig.RouteStrategy.values();
        if (values != null) {
            for (JobConfig.RouteStrategy value : values) {
                result.put(value.getStrategy(), value.getName());
            }
        }
        return result;
    }

    public Map<String, String> getBlockStrategy() {
        Map<String, String> result = new HashMap<>();
        JobConfig.BlockStrategy[] values = JobConfig.BlockStrategy.values();
        if (values != null) {
            for (JobConfig.BlockStrategy value : values) {
                result.put(value.getStrategy(), value.getName());
            }
        }
        return result;
    }

    @Override
    protected String getBasicDir() {
        return "/system/job/job";
    }
}
